home *** CD-ROM | disk | FTP | other *** search
/ InterCD 2000 September / september_2000.iso / intercd / root / ^Linux / WindowMaker / src / kwm.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-03-30  |  42.6 KB  |  1,777 lines

  1. /* kwm.c-- stuff for support for kwm hints
  2.  *
  3.  *  Window Maker window manager
  4.  * 
  5.  *  Copyright (c) 1998, 1999 Alfredo K. Kojima
  6.  * 
  7.  *  This program is free software; you can redistribute it and/or modify
  8.  *  it under the terms of the GNU General Public License as published by
  9.  *  the Free Software Foundation; either version 2 of the License, or
  10.  *  (at your option) any later version.
  11.  *
  12.  *  This program is distributed in the hope that it will be useful,
  13.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  *  GNU General Public License for more details.
  16.  *
  17.  *  You should have received a copy of the GNU General Public License
  18.  *  along with this program; if not, write to the Free Software
  19.  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 
  20.  *  USA.
  21.  */
  22.  
  23. /*
  24.  * 
  25.  * Supported stuff:
  26.  * ================
  27.  * 
  28.  * kfm icon selection from krootbgwm
  29.  * 
  30.  * kwm.h function/method    Notes
  31.  *----------------------------------------------------------------------------
  32.  * setUnsavedDataHint()     currently, only gives visual clue that 
  33.  *                there is unsaved data (broken X close button)
  34.  * setSticky()            
  35.  * setIcon()            std X thing...
  36.  * setDecoration()        
  37.  * logout()
  38.  * refreshScreen()
  39.  * setWmCommand()        std X thing
  40.  * currentDesktop()
  41.  * setKWMModule()
  42.  *
  43.  * isKWMInitialized()        not trustworthy
  44.  * activeWindow()        dunno it's use, but since it's easy to 
  45.  *                 implement it won't hurt to support
  46.  * switchToDesktop()
  47.  * (set/get)WindowRegion()
  48.  * (set)numberOfDesktops()    KDE limits to 32, but wmaker is virtually
  49.  *                 unlimited. May raise some incompatibility
  50.  *                 in badly written KDE modules?
  51.  * (set/get)DesktopName()
  52.  * sendKWMCommand()        also does the message relay thing
  53.  * desktop()
  54.  * geometryRestore()
  55.  * isIconified()        
  56.  * isMaximized()        
  57.  * isSticky()
  58.  * moveToDesktop()        WARNING: evil mechanism
  59.  * setGeometryRestore()        WARNING: evil mechanism
  60.  * setMaximize()        woo hoo! wanna race?
  61.  * setIconify()            BAH!: why reinvent the f'ing wheel!? 
  62.  *                 its even broken!!!
  63.  * move()            std X thing
  64.  * setGeometry()        std X thing
  65.  * close()            std X thing
  66.  * activate()
  67.  * activateInternal()
  68.  * raise()            std X thing
  69.  * lower()            std X thing
  70.  * prepareForSwallowing()    std X thing
  71.  * doNotManage()        klugy thing...
  72.  * getBlablablaString()
  73.  * setKWMDockModule()        maybe we can make the Dock behave as the KDE
  74.  *                 dock, but must figure where to show the windows
  75.  * setDockWindow()
  76.  * 
  77.  * Unsupported stuff (superfluous/not-essential/nonsense):
  78.  * =======================================================
  79.  * 
  80.  * darkenScreen()
  81.  * setMiniIcon()
  82.  * configureWm()
  83.  * raiseSoundEvent()
  84.  * registerSoundEvent()
  85.  * unregisterSoundEvent()
  86.  * title()
  87.  * titleWithState()
  88.  * geometry()            kde lib code makes it unnecessary
  89.  * 
  90.  * 
  91.  * Extensions to KDE:
  92.  * ==================
  93.  * 
  94.  * These are clientmessage-type messages specific to Window Maker:
  95.  * wmaker:info - show info panel
  96.  * wmaker:legal - show legal panel
  97.  * wmaker:arrangeIcons - arrange icons
  98.  * wmaker:showAll - show all windows
  99.  * wmaker:hideOthers - hide others
  100.  * wmaker:restart - restart wmaker
  101.  * wmaker:exit - exit wmaker
  102.  */
  103.  
  104. /*
  105.  * TODO
  106.  * different WORKAREA for each workspace
  107.  */
  108.  
  109.  
  110. #include "wconfig.h"
  111.  
  112. #ifdef KWM_HINTS
  113.  
  114. #include <X11/Xlib.h>
  115. #include <X11/Xutil.h>
  116. #include <X11/Xatom.h>
  117.  
  118. #include <stdlib.h>
  119. #include <stdio.h>
  120. #include <string.h>
  121. #include <unistd.h>
  122.  
  123. #include <sys/types.h>
  124. #include <sys/socket.h>
  125. #include <sys/un.h>
  126. #include <signal.h>
  127.  
  128.  
  129. #include "WindowMaker.h"
  130.  
  131. #include "screen.h"
  132. #include "wcore.h"
  133. #include "framewin.h"
  134. #include "window.h"
  135. #include "properties.h"
  136. #include "icon.h"
  137. #include "client.h"
  138. #include "funcs.h"
  139. #include "actions.h"
  140. #include "workspace.h"
  141. #include "dialog.h"
  142. #include "stacking.h"
  143.  
  144. #include "kwm.h"
  145.  
  146. /*#define DEBUG1
  147. */
  148. /******* Global ******/
  149.  
  150. extern Time LastFocusChange;
  151. extern Time LastTimestamp;
  152.  
  153.  
  154. extern Atom _XA_GNUSTEP_WM_MINIATURIZE_WINDOW;
  155. extern Atom _XA_WM_DELETE_WINDOW;
  156.  
  157. /** Local **/
  158.  
  159. static Atom _XA_KWM_COMMAND = 0;
  160. static Atom _XA_KWM_ACTIVATE_WINDOW = 0;
  161. static Atom _XA_KWM_ACTIVE_WINDOW = 0;
  162. static Atom _XA_KWM_DO_NOT_MANAGE = 0;
  163. static Atom _XA_KWM_DOCKWINDOW = 0;
  164. static Atom _XA_KWM_RUNNING = 0;
  165.  
  166. static Atom _XA_KWM_MODULE = 0;
  167.  
  168. static Atom _XA_KWM_MODULE_INIT = 0;
  169. static Atom _XA_KWM_MODULE_INITIALIZED = 0;
  170. static Atom _XA_KWM_MODULE_DESKTOP_CHANGE = 0;
  171. static Atom _XA_KWM_MODULE_DESKTOP_NAME_CHANGE = 0;
  172. static Atom _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE = 0;
  173. static Atom _XA_KWM_MODULE_WIN_ADD = 0;
  174. static Atom _XA_KWM_MODULE_WIN_REMOVE = 0;
  175. static Atom _XA_KWM_MODULE_WIN_CHANGE = 0;
  176. static Atom _XA_KWM_MODULE_WIN_RAISE = 0;
  177. static Atom _XA_KWM_MODULE_WIN_LOWER = 0;
  178. static Atom _XA_KWM_MODULE_WIN_ACTIVATE = 0;
  179. static Atom _XA_KWM_MODULE_WIN_ICON_CHANGE = 0;
  180. static Atom _XA_KWM_MODULE_DOCKWIN_ADD = 0;
  181. static Atom _XA_KWM_MODULE_DOCKWIN_REMOVE = 0;
  182.   
  183. static Atom _XA_KWM_WIN_UNSAVED_DATA = 0;
  184. static Atom _XA_KWM_WIN_DECORATION = 0;
  185. static Atom _XA_KWM_WIN_DESKTOP = 0;
  186. static Atom _XA_KWM_WIN_GEOMETRY_RESTORE = 0;
  187. static Atom _XA_KWM_WIN_ICONIFIED = 0;
  188. static Atom _XA_KWM_WIN_MAXIMIZED = 0;
  189. static Atom _XA_KWM_WIN_STICKY = 0;
  190.  
  191. static Atom _XA_KWM_WIN_ICON_GEOMETRY = 0;
  192.  
  193. static Atom _XA_KWM_CURRENT_DESKTOP = 0;
  194. static Atom _XA_KWM_NUMBER_OF_DESKTOPS = 0;
  195. static Atom _XA_KWM_DESKTOP_NAME_[MAX_WORKSPACES];
  196. static Atom _XA_KWM_WINDOW_REGION_[MAX_WORKSPACES];
  197.  
  198.  
  199.  
  200. /* list of window titles that must not be managed */
  201. typedef struct KWMDoNotManageList {
  202.     char title[20];
  203.     struct KWMDoNotManageList *next;
  204. } KWMDoNotManageList;
  205.  
  206. static KWMDoNotManageList *KWMDoNotManageCrap = NULL;
  207.  
  208.  
  209. /* list of KWM modules */
  210. typedef struct KWMModuleList {
  211.     Window window;
  212.     struct KWMModuleList *next;
  213. #ifdef DEBUG1
  214.     char *title;
  215. #endif
  216. } KWMModuleList;
  217.  
  218. static KWMModuleList *KWMModules = NULL;
  219.  
  220. static KWMModuleList *KWMDockWindows = NULL;
  221.  
  222. /* window decoration types */
  223. enum {
  224.     KWMnoDecoration = 0, 
  225.     KWMnormalDecoration = 1, 
  226.     KWMtinyDecoration = 2,
  227.     KWMnoFocus = 256,
  228.     KWMstandaloneMenuBar = 512, 
  229.     KWMdesktopIcon = 1024,
  230.     KWMstaysOnTop = 2048
  231. };
  232.  
  233.  
  234.  
  235. static Bool
  236. getSimpleHint(Window win, Atom atom, long *retval)
  237. {
  238.     long *data = 0;
  239.  
  240.     assert(atom!=0);
  241.  
  242.     data = (long*)PropGetCheckProperty(win, atom, atom, 32, 1, NULL);
  243.  
  244.     if (!data)
  245.     return False;
  246.  
  247.     *retval = *data;
  248.  
  249.     XFree(data);
  250.  
  251.     return True;
  252. }
  253.  
  254.  
  255.  
  256. static void
  257. setSimpleHint(Window win, Atom atom, long value)
  258. {
  259.     assert(atom!=0);
  260.     XChangeProperty(dpy, win, atom, atom,
  261.             32, PropModeReplace, (unsigned char*)&value, 1);
  262. }
  263.  
  264.  
  265. static void
  266. sendClientMessage(WScreen *scr, Window window, Atom atom, long value)
  267. {
  268.     XEvent event;
  269.     long mask = 0;
  270.  
  271.     assert(atom!=0);
  272.  
  273.     memset(&event, 0, sizeof(XEvent));
  274.     event.xclient.type = ClientMessage;
  275.     event.xclient.message_type = atom;
  276.     event.xclient.window = window;
  277.     event.xclient.format = 32;
  278.     event.xclient.data.l[0] = value;
  279.     event.xclient.data.l[1] = LastTimestamp;
  280.  
  281.     if (scr && scr->root_win == window)
  282.     mask = SubstructureRedirectMask;
  283.  
  284.     XSendEvent(dpy, window, False, mask, &event);
  285. }
  286.  
  287.  
  288. static void
  289. sendTextMessage(WScreen *scr, Window window, Atom atom, char *text)
  290. {
  291.     XEvent event;
  292.     long mask = 0;
  293.     int i;
  294.  
  295.     assert(atom!=0);
  296.  
  297.     memset(&event, 0, sizeof(XEvent));
  298.     event.xclient.type = ClientMessage;
  299.     event.xclient.message_type = atom;
  300.     event.xclient.window = window;
  301.     event.xclient.format = 8;
  302.  
  303.     for (i=0; i<20 && text[i]; i++)
  304.     event.xclient.data.b[i] = text[i];
  305.  
  306.     if (scr && scr->root_win == window)
  307.     mask = SubstructureRedirectMask;
  308.  
  309.     XSendEvent(dpy, window, False, mask, &event);
  310. }
  311.  
  312.  
  313. static Bool
  314. getAreaHint(Window win, Atom atom, WArea *area)
  315. {
  316.     long *data = 0;
  317.  
  318.     data = (long*)PropGetCheckProperty(win, atom, atom, 32, 4, NULL);
  319.  
  320.     if (!data)
  321.     return False;
  322.  
  323.     area->x1 = data[0];
  324.     area->y1 = data[1];
  325.     area->x2 = data[2] + area->x1;
  326.     area->y2 = data[3] + area->y1;
  327.  
  328.     XFree(data);
  329.  
  330.     return True;
  331. }
  332.  
  333.  
  334. static void
  335. setAreaHint(Window win, Atom atom, WArea area)
  336. {
  337.     long value[4];
  338.  
  339.     assert(atom!=0);
  340.     value[0] = area.x1;
  341.     value[1] = area.y1;
  342.     value[2] = area.x2 - area.x1;
  343.     value[3] = area.y2 - area.y1;
  344.     XChangeProperty(dpy, win, atom, atom, 32, PropModeReplace, 
  345.             (unsigned char*)&value, 4);
  346. }
  347.  
  348.  
  349. static void
  350. addModule(WScreen *scr, Window window)
  351. {
  352.     KWMModuleList *node;
  353.     long val;
  354.     WWindow *ptr;
  355.  
  356.     node = malloc(sizeof(KWMModuleList));
  357.     if (!node) {
  358.     wwarning("out of memory while registering KDE module");
  359.     return;
  360.     }
  361.  
  362.     node->next = KWMModules;
  363.     node->window = window;
  364.     KWMModules = node;
  365.  
  366.     sendClientMessage(scr, window, _XA_KWM_MODULE_INIT, 0);
  367.  
  368.     if (getSimpleHint(window, _XA_KWM_MODULE, &val) && val==2) {
  369.     if (scr->kwm_dock != None) {
  370.         setSimpleHint(window, _XA_KWM_MODULE, 1);
  371.     } else {
  372.         KWMModuleList *ptr;
  373.         
  374.         scr->kwm_dock = window;
  375.  
  376.         for (ptr = KWMDockWindows; ptr!=NULL; ptr = ptr->next) {
  377.         sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_ADD,
  378.                   ptr->window);
  379.         }
  380.     }
  381.     }
  382.  
  383.     /* send list of windows */
  384.     for (ptr = scr->focused_window; ptr!=NULL; ptr = ptr->prev) {
  385.     if (!ptr->flags.kwm_hidden_for_modules
  386.         && !WFLAGP(ptr, skip_window_list)) {
  387.         sendClientMessage(scr, window, _XA_KWM_MODULE_WIN_ADD,
  388.                   ptr->client_win);
  389.     }
  390.     }
  391.  
  392.     /* send window stacking order */
  393.     wKWMSendStacking(scr, window);
  394.  
  395.     /* send focused window */
  396.     if (scr->focused_window && scr->focused_window->flags.focused) {
  397.     sendClientMessage(scr, window, _XA_KWM_MODULE_WIN_ACTIVATE,
  398.               scr->focused_window->client_win);
  399.     }
  400.  
  401.     /* tell who we are */
  402.     sendTextMessage(scr, window, _XA_KWM_COMMAND, "wm:wmaker");
  403.  
  404.  
  405.     sendClientMessage(scr, window, _XA_KWM_MODULE_INITIALIZED, 0);
  406. #ifdef DEBUG1
  407.     KWMModules->title = NULL;
  408.     XFetchName(dpy, window, &KWMModules->title);
  409.     printf("NEW MODULE %s\n", KWMModules->title);
  410. #endif
  411. }
  412.  
  413.  
  414. static void
  415. removeModule(WScreen *scr, Window window)
  416. {
  417.     KWMModuleList *next;
  418.  
  419.     if (!KWMModules) {
  420.     return;
  421.     }
  422.  
  423.     if (KWMModules->window == window) {
  424.     next = KWMModules->next;
  425. #ifdef DEBUG1
  426.     printf("REMOVING MODULE %s\n", KWMModules->title);
  427.     if (KWMModules->title)
  428.         XFree(KWMModules->title);
  429. #endif
  430.     free(KWMModules);
  431.     KWMModules = next;
  432.     } else {
  433.     KWMModuleList *ptr;
  434.  
  435.     ptr = KWMModules;
  436.     while (ptr->next) {
  437.         if (ptr->next->window == window) {
  438.         next = ptr->next->next;
  439. #ifdef DEBUG1
  440.         printf("REMOVING MODULE %s\n", ptr->next->title);
  441.         if (ptr->next->title)
  442.             XFree(ptr->next->title);
  443. #endif
  444.         free(ptr->next);
  445.         ptr->next->next = next;
  446.         break;
  447.         }
  448.         ptr->next = ptr->next->next;
  449.     }
  450.     }
  451.  
  452.     if (scr->kwm_dock == window)
  453.     scr->kwm_dock = None;
  454. }
  455.  
  456.  
  457.  
  458. static void
  459. addDockWindow(WScreen *scr, Window window)
  460. {
  461.     KWMModuleList *ptr;
  462.  
  463.     for (ptr = KWMDockWindows; ptr != NULL; ptr = ptr->next) {
  464.     if (ptr->window == window)
  465.         break;
  466.     }
  467.     if (!ptr) {
  468.     KWMModuleList *node;
  469.  
  470.     node = malloc(sizeof(KWMModuleList));
  471.     if (!node) {
  472.         wwarning("out of memory while processing KDE dock window");
  473.         return;
  474.     }
  475.     node->next = KWMDockWindows;
  476.     KWMDockWindows = node;
  477.     node->window = window;
  478.     XSelectInput(dpy, window, StructureNotifyMask);
  479.  
  480.     sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_ADD,
  481.               window);
  482.     }
  483. }
  484.  
  485.  
  486. static void
  487. removeDockWindow(WScreen *scr, Window window)
  488. {
  489.     if (!KWMDockWindows)
  490.     return;
  491.  
  492.     if (KWMDockWindows->window == window) {
  493.     KWMModuleList *next;
  494.  
  495.     sendClientMessage(scr, scr->kwm_dock, _XA_KWM_MODULE_DOCKWIN_REMOVE,
  496.               window);
  497.  
  498.     next = KWMDockWindows->next;
  499.     free(KWMDockWindows);
  500.     KWMDockWindows = next;
  501.  
  502.     } else {
  503.     KWMModuleList *ptr, *next;
  504.  
  505.     ptr = KWMDockWindows;
  506.     while (ptr->next) {
  507.         if (ptr->next->window == window) {
  508.         sendClientMessage(scr, scr->kwm_dock,
  509.                   _XA_KWM_MODULE_DOCKWIN_REMOVE, window);
  510.         next = ptr->next->next;
  511.         free(ptr->next);
  512.         ptr->next = next;
  513.         return;
  514.         }
  515.         ptr = ptr->next;
  516.     }
  517.     }
  518. }
  519.  
  520.  
  521. static void
  522. sendToModules(WScreen *scr, Atom atom, WWindow *wwin, long data)
  523. {
  524.     KWMModuleList *ptr;
  525.     XEvent event;
  526.     long mask;
  527.  
  528.     if (wwin) {
  529.     if (wwin->flags.kwm_hidden_for_modules
  530.         || WFLAGP(wwin, skip_window_list))
  531.         return;
  532.     data = wwin->client_win;
  533.     }
  534. #ifdef DEBUG1    
  535.     printf("notifying %s\n",XGetAtomName(dpy, atom));
  536. #endif
  537.     memset(&event, 0, sizeof(XEvent));
  538.     event.xclient.type = ClientMessage;
  539.     event.xclient.message_type = atom;
  540.     event.xclient.format = 32;
  541.     event.xclient.data.l[1] = LastTimestamp;
  542.  
  543.     mask = 0;
  544.     if (scr && scr->root_win == data)
  545.     mask = SubstructureRedirectMask;
  546.  
  547.     for (ptr = KWMModules; ptr!=NULL; ptr = ptr->next) {
  548.     event.xclient.window = ptr->window;
  549.     event.xclient.data.l[0] = data;
  550.     XSendEvent(dpy, ptr->window, False, mask, &event);
  551.     }
  552. }
  553.  
  554.  
  555. void
  556. wKWMInitStuff(WScreen *scr)
  557. {
  558.     if (!_XA_KWM_WIN_STICKY) {
  559.     _XA_KWM_WIN_UNSAVED_DATA = XInternAtom(dpy, "KWM_WIN_UNSAVED_DATA",
  560.                            False);
  561.  
  562.     _XA_KWM_WIN_DECORATION = XInternAtom(dpy, "KWM_WIN_DECORATION", False);
  563.  
  564.     _XA_KWM_WIN_DESKTOP = XInternAtom(dpy, "KWM_WIN_DESKTOP", False);
  565.  
  566.     _XA_KWM_WIN_GEOMETRY_RESTORE = XInternAtom(dpy, 
  567.                            "KWM_WIN_GEOMETRY_RESTORE",
  568.                            False);
  569.  
  570.     _XA_KWM_WIN_STICKY = XInternAtom(dpy, "KWM_WIN_STICKY", False);
  571.  
  572.     _XA_KWM_WIN_ICONIFIED = XInternAtom(dpy, "KWM_WIN_ICONIFIED", False);
  573.  
  574.     _XA_KWM_WIN_MAXIMIZED = XInternAtom(dpy, "KWM_WIN_MAXIMIZED", False);
  575.  
  576.     _XA_KWM_WIN_ICON_GEOMETRY = XInternAtom(dpy, "KWM_WIN_ICON_GEOMETRY",
  577.                         False);
  578.  
  579.     _XA_KWM_COMMAND = XInternAtom(dpy, "KWM_COMMAND", False);
  580.  
  581.     _XA_KWM_ACTIVE_WINDOW = XInternAtom(dpy, "KWM_ACTIVE_WINDOW", False);
  582.  
  583.     _XA_KWM_ACTIVATE_WINDOW = XInternAtom(dpy, "KWM_ACTIVATE_WINDOW",
  584.                           False);
  585.  
  586.     _XA_KWM_DO_NOT_MANAGE = XInternAtom(dpy, "KWM_DO_NOT_MANAGE", False);
  587.     
  588.     _XA_KWM_CURRENT_DESKTOP = XInternAtom(dpy, "KWM_CURRENT_DESKTOP", 
  589.                           False);
  590.  
  591.     _XA_KWM_NUMBER_OF_DESKTOPS = XInternAtom(dpy, "KWM_NUMBER_OF_DESKTOPS",
  592.                          False);
  593.  
  594.     _XA_KWM_DOCKWINDOW = XInternAtom(dpy, "KWM_DOCKWINDOW", False);
  595.  
  596.     _XA_KWM_RUNNING = XInternAtom(dpy, "KWM_RUNNING", False);
  597.  
  598.     _XA_KWM_MODULE = XInternAtom(dpy, "KWM_MODULE", False);
  599.  
  600.     _XA_KWM_MODULE_INIT = XInternAtom(dpy, "KWM_MODULE_INIT", False);
  601.     _XA_KWM_MODULE_INITIALIZED = XInternAtom(dpy, "KWM_MODULE_INITIALIZED", False);
  602.  
  603.     /* dunno what these do, but Matthias' patch contains it... */
  604.     _XA_KWM_MODULE_DESKTOP_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_CHANGE", False);
  605.     _XA_KWM_MODULE_DESKTOP_NAME_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_NAME_CHANGE", False);
  606.     _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE = XInternAtom(dpy, "KWM_MODULE_DESKTOP_NUMBER_CHANGE", False);
  607.  
  608.     _XA_KWM_MODULE_WIN_ADD = XInternAtom(dpy, "KWM_MODULE_WIN_ADD", False);
  609.     _XA_KWM_MODULE_WIN_REMOVE = XInternAtom(dpy, "KWM_MODULE_WIN_REMOVE", False);
  610.     _XA_KWM_MODULE_WIN_CHANGE = XInternAtom(dpy, "KWM_MODULE_WIN_CHANGE", False);
  611.     _XA_KWM_MODULE_WIN_RAISE = XInternAtom(dpy, "KWM_MODULE_WIN_RAISE", False);
  612.     _XA_KWM_MODULE_WIN_LOWER = XInternAtom(dpy, "KWM_MODULE_WIN_LOWER", False);
  613.     _XA_KWM_MODULE_WIN_ACTIVATE = XInternAtom(dpy, "KWM_MODULE_WIN_ACTIVATE", False);
  614.     _XA_KWM_MODULE_WIN_ICON_CHANGE = XInternAtom(dpy, "KWM_MODULE_WIN_ICON_CHANGE", False);
  615.     _XA_KWM_MODULE_DOCKWIN_ADD = XInternAtom(dpy, "KWM_MODULE_DOCKWIN_ADD", False);
  616.     _XA_KWM_MODULE_DOCKWIN_REMOVE = XInternAtom(dpy, "KWM_MODULE_DOCKWIN_REMOVE", False);
  617.     
  618.     memset(_XA_KWM_WINDOW_REGION_, 0, sizeof(_XA_KWM_WINDOW_REGION_));
  619.  
  620.     memset(_XA_KWM_DESKTOP_NAME_, 0, sizeof(_XA_KWM_DESKTOP_NAME_));
  621.     }
  622.  
  623. #define SETSTR(hint, str) {\
  624.     static Atom a = 0; if (!a) a = XInternAtom(dpy, #hint, False);\
  625.     XChangeProperty(dpy, scr->root_win, a, XA_STRING, 8, PropModeReplace,\
  626.                 (unsigned char*)str, strlen(str));}
  627.  
  628.     SETSTR(KWM_STRING_MAXIMIZE, _("Maximize"));
  629.     SETSTR(KWM_STRING_UNMAXIMIZE, _("Unmaximize"));
  630.     SETSTR(KWM_STRING_ICONIFY, _("Miniaturize"));
  631.     SETSTR(KWM_STRING_UNICONIFY, _("Deminiaturize"));
  632.     SETSTR(KWM_STRING_STICKY, _("Omnipresent"));
  633.     SETSTR(KWM_STRING_UNSTICKY, _("Not Omnipresent"));
  634.     SETSTR(KWM_STRING_STRING_MOVE, _("Move"));
  635.     SETSTR(KWM_STRING_STRING_RESIZE, _("Resize"));
  636.     SETSTR(KWM_STRING_CLOSE, _("Close"));
  637.     SETSTR(KWM_STRING_TODESKTOP, _("Move To"));
  638.     SETSTR(KWM_STRING_ONTOCURRENTDESKTOP, _("Bring Here"));
  639. #undef SETSTR
  640. }
  641.  
  642.  
  643. void
  644. wKWMSendStacking(WScreen *scr, Window module)
  645. {
  646.     WMBagIterator i;
  647.     WCoreWindow *core;
  648.  
  649.     WM_ITERATE_BAG(scr->stacking_list, core, i) {
  650.     for (; core != NULL; core = core->stacking->under) {
  651.         WWindow *wwin;
  652.  
  653.         wwin = wWindowFor(core->window);
  654.         if (wwin)
  655.         sendClientMessage(scr, module, _XA_KWM_MODULE_WIN_RAISE,
  656.                   wwin->client_win);
  657.     }
  658.     }
  659. }
  660.  
  661.  
  662. void
  663. wKWMBroadcastStacking(WScreen *scr)
  664. {
  665.     KWMModuleList *ptr = KWMModules;
  666.  
  667.     while (ptr) {
  668.     wKWMSendStacking(scr, ptr->window);
  669.  
  670.     ptr = ptr->next;
  671.     }
  672. }
  673.  
  674.  
  675. char*
  676. wKWMGetWorkspaceName(WScreen *scr, int workspace)
  677. {
  678.     Atom type_ret;
  679.     int fmt_ret;
  680.     unsigned long nitems_ret;
  681.     unsigned long bytes_after_ret;
  682.     char *data = NULL, *tmp;
  683.     char buffer[64];
  684.  
  685.     assert(workspace >= 0 && workspace < MAX_WORKSPACES);
  686.  
  687.     if (_XA_KWM_DESKTOP_NAME_[workspace]==0) {
  688.     sprintf(buffer, "KWM_DESKTOP_NAME_%d", workspace + 1);
  689.  
  690.     _XA_KWM_DESKTOP_NAME_[workspace] = XInternAtom(dpy, buffer, False);
  691.     }
  692.     
  693.     /* What do these people have against correctly using property types? */
  694.     if (XGetWindowProperty(dpy, scr->root_win, 
  695.                _XA_KWM_DESKTOP_NAME_[workspace], 0, 128, False, 
  696.                XA_STRING,
  697.                &type_ret, &fmt_ret, &nitems_ret, &bytes_after_ret,
  698.                (unsigned char**)&data)!=Success || !data)
  699.     return NULL;
  700.  
  701.     tmp = wstrdup(data);
  702.     XFree(data);
  703.  
  704.     return tmp;
  705. }
  706.  
  707.  
  708. void
  709. wKWMSetInitializedHint(WScreen *scr)
  710. {
  711.     setSimpleHint(scr->root_win, _XA_KWM_RUNNING, 1);
  712. }
  713.  
  714.  
  715. void
  716. wKWMShutdown(WScreen *scr, Bool closeModules)
  717. {
  718.     KWMModuleList *ptr;
  719.  
  720.     XDeleteProperty(dpy, scr->root_win, _XA_KWM_RUNNING);
  721.  
  722.     if (closeModules) {
  723.     for (ptr = KWMModules; ptr != NULL; ptr = ptr->next) {
  724.         XKillClient(dpy, ptr->window);
  725.     }
  726.     }
  727. }
  728.  
  729.  
  730. void
  731. wKWMCheckClientHints(WWindow *wwin, int *layer, int *workspace)
  732. {
  733.     long val;
  734.  
  735.     if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_UNSAVED_DATA, &val)    
  736.     && val) {
  737.  
  738.     wwin->client_flags.broken_close = 1;
  739.     }
  740.     if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DECORATION, &val)) {
  741.     if (val & KWMnoFocus) {
  742.         wwin->client_flags.no_focusable = 1;
  743.     }
  744.     switch (val & ~KWMnoFocus) {
  745.      case KWMnoDecoration:
  746.         wwin->client_flags.no_titlebar = 1;
  747.         wwin->client_flags.no_resizebar = 1;
  748.         break;
  749.      case KWMtinyDecoration:
  750.         wwin->client_flags.no_resizebar = 1;
  751.         break;
  752.      case KWMstandaloneMenuBar:
  753.         wwin->client_flags.no_titlebar = 1;
  754.         wwin->client_flags.no_resizebar = 1;
  755.         wwin->client_flags.no_resizable = 1;
  756.         wwin->client_flags.skip_window_list = 1;
  757.         wwin->client_flags.no_hide_others = 1;
  758.         wwin->flags.kwm_menubar = 1;
  759.         *layer = WMMainMenuLevel;
  760.         break;
  761.      case KWMdesktopIcon:
  762.         *layer = WMDesktopLevel;
  763.         break;
  764.      case KWMstaysOnTop:
  765.         *layer = WMFloatingLevel;
  766.         break;
  767.      case KWMnormalDecoration:
  768.      default:
  769.         break;
  770.     }
  771.     }
  772.     if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP, &val)) {
  773.     *workspace = val - 1;
  774.     }
  775. }
  776.  
  777.  
  778. void
  779. wKWMCheckClientInitialState(WWindow *wwin)
  780. {
  781.     long val;
  782.     WArea area;
  783.  
  784.     if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY, &val) && val) {
  785.  
  786.     wwin->client_flags.omnipresent = 1;
  787.     }
  788.     if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED, &val) && val) {
  789.  
  790.     wwin->flags.miniaturized = 1;
  791.     }
  792.     if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED, &val) && val) {
  793.  
  794.     wwin->flags.maximized = MAX_VERTICAL|MAX_HORIZONTAL;
  795.     }
  796.     if (getAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, &area)
  797.     && (wwin->old_geometry.x != area.x1
  798.         || wwin->old_geometry.y != area.y1
  799.         || wwin->old_geometry.width != area.x2 - area.x1
  800.         || wwin->old_geometry.height != area.y2 - area.y1)) {
  801.  
  802.     wwin->old_geometry.x = area.x1;
  803.     wwin->old_geometry.y = area.y1;
  804.     wwin->old_geometry.width = area.x2 - area.x1;
  805.     wwin->old_geometry.height = area.y2 - area.y1;
  806.     }
  807. }
  808.  
  809.  
  810. Bool
  811. wKWMCheckClientHintChange(WWindow *wwin, XPropertyEvent *event)
  812. {
  813.     Bool processed = True;
  814.     Bool flag;
  815.     long value;
  816.  
  817.  
  818.     if (!wwin->frame) {
  819.     return False;
  820.     }
  821.     
  822.     if (event->atom == _XA_KWM_WIN_UNSAVED_DATA) {
  823. #ifdef DEBUG1
  824.     printf("got KDE unsaved data change\n");
  825. #endif
  826.  
  827.     flag = getSimpleHint(wwin->client_win, _XA_KWM_WIN_UNSAVED_DATA,
  828.                  &value) && value;
  829.  
  830.     if (flag != wwin->client_flags.broken_close) {
  831.         wwin->client_flags.broken_close = flag;
  832.         if (wwin->frame)
  833.         wWindowUpdateButtonImages(wwin);
  834.     }
  835.     } else if (event->atom == _XA_KWM_WIN_STICKY) {
  836.  
  837. #ifdef DEBUG1
  838.     printf("got KDE sticky change\n");
  839. #endif
  840.     flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY, 
  841.                   &value) || value;
  842.  
  843.     if (flag != wwin->client_flags.omnipresent) {
  844.  
  845.         wwin->client_flags.omnipresent = flag;
  846.  
  847.         UpdateSwitchMenu(wwin->screen_ptr, wwin, ACTION_CHANGE_WORKSPACE);
  848.  
  849.     }
  850.     } else if (event->atom == _XA_KWM_WIN_MAXIMIZED) {
  851.  
  852. #ifdef DEBUG1
  853.     printf("got KDE maximize change\n");
  854. #endif
  855.     flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED,
  856.                  &value) || value;
  857.  
  858.     if (flag != (wwin->flags.maximized!=0)) {
  859.  
  860.         if (flag)
  861.         wMaximizeWindow(wwin, flag*(MAX_VERTICAL|MAX_HORIZONTAL));
  862.         else
  863.         wUnmaximizeWindow(wwin);
  864.     } 
  865.     } else if (event->atom == _XA_KWM_WIN_ICONIFIED) {
  866.  
  867. #ifdef DEBUG1
  868.     printf("got KDE iconify change\n");
  869. #endif
  870.     flag = !getSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED,
  871.                  &value) || value;
  872.  
  873.     if (flag != wwin->flags.miniaturized) {
  874.  
  875.         if (flag)
  876.         wIconifyWindow(wwin);
  877.         else
  878.         wDeiconifyWindow(wwin);
  879.     } 
  880.  
  881.     } else if (event->atom == _XA_KWM_WIN_DECORATION) {
  882.     Bool refresh = False;
  883.     int oldnofocus;
  884.  
  885. #ifdef DEBUG1
  886.     printf("got KDE decoration change\n");
  887. #endif
  888.  
  889.     oldnofocus = wwin->client_flags.no_focusable;
  890.  
  891.     if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DECORATION, &value)) {
  892.         wwin->client_flags.no_focusable = (value & KWMnoFocus)!=0;
  893.  
  894.         switch (value & ~KWMnoFocus) {
  895.          case KWMnoDecoration:
  896.         if (!WFLAGP(wwin, no_titlebar) || !WFLAGP(wwin, no_resizebar))
  897.             refresh = True;
  898.  
  899.         wwin->client_flags.no_titlebar = 1;
  900.         wwin->client_flags.no_resizebar = 1;
  901.         break;
  902.  
  903.          case KWMtinyDecoration:
  904.         if (WFLAGP(wwin, no_titlebar) || !WFLAGP(wwin, no_resizebar))
  905.             refresh = True;
  906.  
  907.         wwin->client_flags.no_titlebar = 0;
  908.         wwin->client_flags.no_resizebar = 1;
  909.         break;
  910.  
  911.          case KWMnormalDecoration:
  912.          default:
  913.         if (WFLAGP(wwin, no_titlebar) || WFLAGP(wwin, no_resizebar))
  914.             refresh = True;
  915.  
  916.         wwin->client_flags.no_titlebar = 0;
  917.         wwin->client_flags.no_resizebar = 0;
  918.         break;
  919.         }
  920.     } else {
  921.         if (WFLAGP(wwin, no_titlebar) || WFLAGP(wwin, no_resizebar))
  922.         refresh = True;
  923.         wwin->client_flags.no_focusable = (value & KWMnoFocus)!=0;
  924.         wwin->client_flags.no_titlebar = 0;
  925.         wwin->client_flags.no_resizebar = 0;
  926.     }
  927.  
  928.     if (refresh)
  929.         wWindowConfigureBorders(wwin);
  930.  
  931.     if (wwin->client_flags.no_focusable && !oldnofocus) {
  932.  
  933.         sendToModules(wwin->screen_ptr, _XA_KWM_MODULE_WIN_REMOVE, 
  934.               wwin, 0);
  935.         wwin->flags.kwm_hidden_for_modules = 1;
  936.  
  937.     } else if (!wwin->client_flags.no_focusable && oldnofocus) {
  938.  
  939.         if (wwin->flags.kwm_hidden_for_modules) {
  940.         sendToModules(wwin->screen_ptr, _XA_KWM_MODULE_WIN_ADD,
  941.                   wwin, 0);
  942.         wwin->flags.kwm_hidden_for_modules = 0;
  943.         }
  944.     }
  945.     } else if (event->atom == _XA_KWM_WIN_DESKTOP && wwin->frame) {
  946. #ifdef DEBUG1
  947.     printf("got KDE workspace change for %s\n", wwin->frame->title);
  948. #endif
  949.     if (getSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP, &value)
  950.         && value-1 != wwin->frame->workspace) {
  951.         wWindowChangeWorkspace(wwin, value-1);
  952.     }
  953.  
  954.     } else if (event->atom == _XA_KWM_WIN_GEOMETRY_RESTORE) {
  955.     WArea area;
  956.  
  957. #ifdef DEBUG1
  958.     printf("got KDE geometry restore change\n");
  959. #endif
  960.     if (getAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE,    &area)
  961.         && (wwin->old_geometry.x != area.x1
  962.         || wwin->old_geometry.y != area.y1
  963.         || wwin->old_geometry.width != area.x2 - area.x1
  964.         || wwin->old_geometry.height != area.y2 - area.y1)) {
  965.  
  966.         wwin->old_geometry.x = area.x1;
  967.         wwin->old_geometry.y = area.y1;
  968.         wwin->old_geometry.width = area.x2 - area.x1;
  969.         wwin->old_geometry.height = area.y2 - area.y1;
  970.         }
  971.     } else {
  972.     processed = False;
  973.     }
  974.  
  975.     return processed;
  976. }
  977.  
  978.  
  979. static Bool
  980. performWindowCommand(WScreen *scr, char *command)
  981. {
  982.     WWindow *wwin = NULL;
  983.  
  984.  
  985.     wwin = scr->focused_window;
  986.     if (!wwin || !wwin->flags.focused || !wwin->flags.mapped) {
  987.     wwin = NULL;
  988.     }
  989.  
  990.     CloseWindowMenu(scr);
  991.  
  992.  
  993.     if (strcmp(command, "winMove")==0 || strcmp(command, "winResize")==0) {
  994.  
  995.     if (wwin)
  996.         wKeyboardMoveResizeWindow(wwin);
  997.  
  998.     } else if (strcmp(command, "winMaximize")==0) {
  999.  
  1000.     if (wwin)
  1001.         wMaximizeWindow(wwin, MAX_VERTICAL|MAX_HORIZONTAL);
  1002.     
  1003.     } else if (strcmp(command, "winRestore")==0) {
  1004.  
  1005.     if (wwin && wwin->flags.maximized)
  1006.         wUnmaximizeWindow(wwin);
  1007.  
  1008.     } else if (strcmp(command, "winIconify")==0) {
  1009.  
  1010.  
  1011.     if (wwin && !WFLAGP(wwin, no_miniaturizable)) {
  1012.         if (wwin->protocols.MINIATURIZE_WINDOW)
  1013.         wClientSendProtocol(wwin, _XA_GNUSTEP_WM_MINIATURIZE_WINDOW,
  1014.                     LastTimestamp);
  1015.         else {
  1016.         wIconifyWindow(wwin);
  1017.         }
  1018.     }
  1019.  
  1020.     } else if (strcmp(command, "winClose")==0) {
  1021.  
  1022.     if (wwin && !WFLAGP(wwin, no_closable)) {
  1023.         if (wwin->protocols.DELETE_WINDOW)
  1024.         wClientSendProtocol(wwin, _XA_WM_DELETE_WINDOW, LastTimestamp);
  1025.     }
  1026.  
  1027.     } else if (strcmp(command, "winSticky")==0) {
  1028.  
  1029.     if (wwin) {
  1030.         wwin->client_flags.omnipresent ^= 1;
  1031.         UpdateSwitchMenu(scr, wwin, ACTION_CHANGE_WORKSPACE);
  1032.     }
  1033.  
  1034.     } else if (strcmp(command, "winShade")==0) {
  1035.  
  1036.     if (wwin && !WFLAGP(wwin, no_shadeable)) {
  1037.         if (wwin->flags.shaded)
  1038.         wUnshadeWindow(wwin);
  1039.         else
  1040.         wShadeWindow(wwin);
  1041.     }
  1042.  
  1043.     } else if (strcmp(command, "winOperation")==0) {
  1044.  
  1045.     if (wwin)
  1046.         OpenWindowMenu(wwin, wwin->frame_x, 
  1047.                wwin->frame_y+wwin->frame->top_width, True);
  1048.     
  1049.     } else {
  1050.     return False;
  1051.     }
  1052.  
  1053.     return True;
  1054. }
  1055.  
  1056.  
  1057. static void
  1058. performCommand(WScreen *scr, char *command, XClientMessageEvent *event)
  1059. {
  1060.     assert(scr != NULL);
  1061.     
  1062.     if (strcmp(command, "commandLine")==0
  1063.        || strcmp(command, "execute")==0) {
  1064.     char *cmd;
  1065.  
  1066.     cmd = ExpandOptions(scr, _("%a(Run Command,Type the command to run:)"));
  1067.     if (cmd) {
  1068.         ExecuteShellCommand(scr, cmd);
  1069.         free(cmd);
  1070.     }
  1071.     } else if (strcmp(command, "logout")==0) {
  1072.  
  1073.     Shutdown(WSLogoutMode);
  1074.  
  1075.     } else if (strcmp(command, "refreshScreen")==0) {
  1076.  
  1077.     wRefreshDesktop(scr);
  1078.  
  1079.     } else if (strncmp(command, "go:", 3)==0) {
  1080.  
  1081.     Shutdown(WSRestartPreparationMode);
  1082.     Restart(&command[3], False);
  1083.     Restart(NULL, True);
  1084.  
  1085.     } else if (strcmp(command, "desktop+1")==0) {
  1086.  
  1087.     wWorkspaceRelativeChange(scr, 1);
  1088.  
  1089.     } else if (strcmp(command, "desktop-1")==0) {
  1090.  
  1091.     wWorkspaceRelativeChange(scr, -1);
  1092.  
  1093.     } else if (strcmp(command, "desktop+2")==0) {
  1094.  
  1095.     wWorkspaceRelativeChange(scr, 2);
  1096.  
  1097.     } else if (strcmp(command, "desktop-2")==0) {
  1098.  
  1099.     wWorkspaceRelativeChange(scr, -2);
  1100.  
  1101.     } else if (strcmp(command, "desktop%%2")==0) {
  1102.  
  1103.     if (scr->current_workspace % 2 == 1)
  1104.         wWorkspaceRelativeChange(scr, 1);
  1105.     else
  1106.         wWorkspaceRelativeChange(scr, -1);
  1107.     } else if (strncmp(command, "desktop", 7)==0) {
  1108.     int ws;
  1109.  
  1110.     ws = atoi(&command[7]);
  1111.     wWorkspaceChange(scr, ws);
  1112.  
  1113.     /* wmaker specific stuff */
  1114.     } else if (strcmp(command, "wmaker:info")==0) {
  1115.  
  1116.     wShowInfoPanel(scr);
  1117.  
  1118.     } else if (strcmp(command, "wmaker:legal")==0) {
  1119.  
  1120.     wShowLegalPanel(scr);
  1121.  
  1122.     } else if (strcmp(command, "wmaker:arrangeIcons")==0) {
  1123.  
  1124.     wArrangeIcons(scr, True);
  1125.  
  1126.     } else if (strcmp(command, "wmaker:showAll")==0) {
  1127.  
  1128.     wShowAllWindows(scr);
  1129.  
  1130.     } else if (strcmp(command, "wmaker:hideOthers")==0) {
  1131.  
  1132.     wHideOtherApplications(scr->focused_window);
  1133.  
  1134.     } else if (strcmp(command, "wmaker:restart")==0) {
  1135.  
  1136.     Shutdown(WSRestartPreparationMode);
  1137.     Restart(NULL, True);
  1138.  
  1139.     } else if (strcmp(command, "wmaker:exit")==0) {
  1140.  
  1141.     Shutdown(WSExitMode);
  1142.  
  1143. #ifdef UNSUPPORTED_STUFF
  1144.     } else if (strcmp(command, "moduleRaised")==0) { /* useless */
  1145.     } else if (strcmp(command, "deskUnclutter")==0) {
  1146.     } else if (strcmp(command, "deskCascade")==0) {
  1147.     } else if (strcmp(command, "configure")==0) {
  1148.     } else if (strcmp(command, "taskManager")==0) {
  1149.     } else if (strcmp(command, "darkenScreen")==0) { /* breaks consistency */
  1150. #endif
  1151.     } else if (!performWindowCommand(scr, command)) {
  1152.     KWMModuleList *module;
  1153.     long mask = 0;
  1154.     XEvent ev;
  1155.     /* do message relay thing */
  1156.  
  1157.     ev.xclient = *event;
  1158.     for (module = KWMModules; module != NULL; module = module->next) {
  1159.  
  1160.         ev.xclient.window = module->window;
  1161.         if (module->window == scr->root_win)
  1162.         mask = SubstructureRedirectMask;
  1163.         else
  1164.         mask = 0;
  1165.  
  1166.         XSendEvent(dpy, module->window, False, mask, &ev);
  1167.     }
  1168.     }
  1169. }
  1170.  
  1171.  
  1172. Bool
  1173. wKWMProcessClientMessage(XClientMessageEvent *event)
  1174. {
  1175.     Bool processed = True;
  1176.     WScreen *scr;
  1177. #ifdef DEBUG1
  1178.     printf("CLIENT MESS %s\n", XGetAtomName(dpy, event->message_type));
  1179. #endif
  1180.     if (event->message_type == _XA_KWM_COMMAND && event->format==8) {
  1181.     char buffer[24];
  1182.     int i;
  1183.  
  1184.     scr = wScreenForRootWindow(event->window);
  1185.  
  1186.     for (i=0; i<20; i++) {
  1187.         buffer[i] = event->data.b[i];
  1188.     }
  1189.     buffer[i] = 0;
  1190.  
  1191. #ifdef DEBUG1
  1192.     printf("got KDE command %s\n", buffer);
  1193. #endif
  1194.     performCommand(scr, buffer, event);
  1195.  
  1196.     } else if (event->message_type == _XA_KWM_ACTIVATE_WINDOW) {
  1197.     WWindow *wwin;
  1198.  
  1199. #ifdef DEBUG1
  1200.     printf("got KDE activate internal\n");
  1201. #endif
  1202.     wwin = wWindowFor(event->data.l[0]);
  1203.  
  1204.     if (wwin)
  1205.         wSetFocusTo(wwin->screen_ptr, wwin);
  1206.  
  1207.     } else if (event->message_type == _XA_KWM_DO_NOT_MANAGE 
  1208.            && event->format == 8) {
  1209.     KWMDoNotManageList *node;
  1210.     int i;
  1211.  
  1212. #ifdef DEBUG1
  1213.     printf("got KDE dont manage\n");
  1214. #endif
  1215.  
  1216.     node = malloc(sizeof(KWMDoNotManageList));
  1217.     if (!node) {
  1218.         wwarning("out of memory processing KWM_DO_NOT_MANAGE message");
  1219.     }
  1220.     for (i=0; i<20 && event->data.b[i]; i++)
  1221.         node->title[i] = event->data.b[i];
  1222.     node->title[i] = 0;
  1223.  
  1224.     node->next = KWMDoNotManageCrap;
  1225.     KWMDoNotManageCrap = node;
  1226.  
  1227.     } else if (event->message_type == _XA_KWM_MODULE) {
  1228.     long val;
  1229.     Window modwin = event->data.l[0];
  1230.  
  1231.     scr = wScreenForRootWindow(event->window);
  1232.  
  1233.     if (getSimpleHint(modwin, _XA_KWM_MODULE, &val) && val) {
  1234. #ifdef DEBUG1
  1235.         puts("got KDE module startup");
  1236. #endif
  1237.         addModule(scr, modwin);
  1238.     } else {
  1239. #ifdef DEBUG1
  1240.         puts("got KDE module finish");
  1241. #endif
  1242.         removeModule(scr, modwin);
  1243.     }
  1244.     } else {
  1245.     processed = False;
  1246.     }
  1247.     
  1248.     return processed;
  1249. }
  1250.  
  1251.  
  1252. void
  1253. wKWMCheckModule(WScreen *scr, Window window)
  1254. {
  1255.     long val;
  1256.  
  1257.     if (getSimpleHint(window, _XA_KWM_MODULE, &val) && val) {
  1258. #ifdef DEBUG1
  1259.     puts("got KDE module startup");
  1260. #endif
  1261.     addModule(scr, window);
  1262.     }
  1263. }
  1264.  
  1265.  
  1266. Bool
  1267. wKWMCheckRootHintChange(WScreen *scr, XPropertyEvent *event)
  1268. {
  1269.     Bool processed = True;
  1270.     long value;
  1271.  
  1272.     if (event->atom == _XA_KWM_CURRENT_DESKTOP) {
  1273.     if (getSimpleHint(scr->root_win, _XA_KWM_CURRENT_DESKTOP, &value)) {
  1274. #ifdef DEBUG1
  1275.         printf("got KDE workspace switch to %li\n", value);
  1276. #endif
  1277.         if (value-1 != scr->current_workspace) {
  1278.         wWorkspaceChange(scr, value-1);
  1279.         }
  1280.     }
  1281.     } else if (event->atom == _XA_KWM_NUMBER_OF_DESKTOPS) {
  1282. #ifdef DEBUG1
  1283.         printf("got KDE workspace number change\n");
  1284. #endif
  1285.  
  1286.     if (getSimpleHint(scr->root_win, _XA_KWM_NUMBER_OF_DESKTOPS, &value)) {
  1287.  
  1288.         /* increasing is easy... */
  1289.         if (value > scr->workspace_count) {
  1290.         scr->flags.kwm_syncing_count = 1;
  1291.  
  1292.         wWorkspaceMake(scr, value - scr->workspace_count);
  1293.  
  1294.         scr->flags.kwm_syncing_count = 0;
  1295.  
  1296.         } else if (value < scr->workspace_count) {
  1297.         int i;
  1298.         Bool rebuild = False;
  1299.  
  1300.         scr->flags.kwm_syncing_count = 1;
  1301.  
  1302.         /* decrease all we can do */
  1303.         for (i = scr->workspace_count; i >= value; i--) {
  1304.             if (!wWorkspaceDelete(scr, i)) {
  1305.             rebuild = True;
  1306.             break;
  1307.             }
  1308.         }
  1309.  
  1310.         scr->flags.kwm_syncing_count = 0;
  1311.  
  1312.         /* someone destroyed a workspace that can't be destroyed. 
  1313.          * Reset the hints to reflect our internal state.
  1314.          */
  1315.         if (rebuild) {
  1316.             wKWMUpdateWorkspaceCountHint(scr);
  1317.         }
  1318.         }
  1319.     }
  1320.     } else {
  1321.     int i;
  1322.  
  1323.     processed = False;
  1324.  
  1325.     for (i = 0; i < MAX_WORKSPACES && i < scr->workspace_count; i++) {
  1326.          if (event->atom == _XA_KWM_DESKTOP_NAME_[i]) {
  1327.          char *name;
  1328.  
  1329.          name = wKWMGetWorkspaceName(scr, i);
  1330.  
  1331. #ifdef DEBUG1
  1332.          printf("got KDE workspace name change to %s\n", name);
  1333. #endif
  1334.  
  1335.          if (name && strncmp(name, scr->workspaces[i]->name, 
  1336.                      MAX_WORKSPACENAME_WIDTH)!=0) {
  1337.              scr->flags.kwm_syncing_name = 1;
  1338.              wWorkspaceRename(scr, i, name);
  1339.              scr->flags.kwm_syncing_name = 0;
  1340.          }
  1341.          if (name)
  1342.              XFree(name);
  1343.          processed = True;
  1344.          break;
  1345.          } else if (event->atom == _XA_KWM_WINDOW_REGION_[i]) {
  1346.          WArea area;
  1347.  
  1348.          if (getAreaHint(scr->root_win, event->atom, &area)) {
  1349.                 
  1350.              if (scr->totalUsableArea.x1 != area.x1
  1351.              || scr->totalUsableArea.y1 != area.y1
  1352.              || scr->totalUsableArea.x2 != area.x2
  1353.              || scr->totalUsableArea.y2 != area.y2) {
  1354.              wScreenUpdateUsableArea(scr);
  1355.              }
  1356.          }
  1357.  
  1358.          processed = True;
  1359.          break;
  1360.          }
  1361.     }
  1362.     }
  1363.  
  1364.     return processed;
  1365. }
  1366.  
  1367.  
  1368. Bool
  1369. wKWMManageableClient(WScreen *scr, Window win, char *title)
  1370. {
  1371.     KWMDoNotManageList *ptr, *next;
  1372.     long val;
  1373.  
  1374.     if (getSimpleHint(win, _XA_KWM_DOCKWINDOW, &val) && val) {
  1375.     addDockWindow(scr, win);
  1376.     return False;
  1377.     }
  1378.     
  1379.     ptr = KWMDoNotManageCrap;
  1380.     /*
  1381.      * TODO: support for glob patterns or regexes
  1382.      */
  1383.     if (ptr && strncmp(ptr->title, title, strlen(ptr->title))==0) {
  1384.     next = ptr->next;
  1385.     free(ptr);
  1386.     KWMDoNotManageCrap = next;
  1387. #ifdef DEBUG1
  1388.     printf("window %s not managed per KDE request\n", title);
  1389. #endif
  1390.  
  1391.     sendToModules(scr, _XA_KWM_MODULE_WIN_ADD, NULL, win);
  1392.     sendToModules(scr, _XA_KWM_MODULE_WIN_REMOVE, NULL, win);
  1393.  
  1394.     return False;
  1395.     } else if (ptr) {
  1396.     while (ptr->next) {
  1397.         if (strncmp(ptr->next->title, title, strlen(ptr->next->title))==0) {
  1398. #ifdef DEBUG1
  1399.         printf("window %s not managed per KDE request\n", title);
  1400. #endif
  1401.         next = ptr->next->next;
  1402.         free(ptr->next);
  1403.         ptr->next = next;
  1404.  
  1405.         sendToModules(scr, _XA_KWM_MODULE_WIN_ADD, NULL, win);
  1406.         sendToModules(scr, _XA_KWM_MODULE_WIN_REMOVE, NULL, win);
  1407.  
  1408.         return False;
  1409.         }
  1410.  
  1411.         ptr = ptr->next;
  1412.     }
  1413.     }
  1414.  
  1415.     return True;
  1416. }
  1417.  
  1418.  
  1419. void
  1420. wKWMUpdateCurrentWorkspaceHint(WScreen *scr)
  1421. {
  1422.     setSimpleHint(scr->root_win, _XA_KWM_CURRENT_DESKTOP,
  1423.           scr->current_workspace+1);
  1424.  
  1425.     sendToModules(scr, _XA_KWM_MODULE_DESKTOP_CHANGE, NULL,
  1426.           scr->current_workspace+1);
  1427. }
  1428.  
  1429.  
  1430. void
  1431. wKWMUpdateActiveWindowHint(WScreen *scr)
  1432. {
  1433.     long val;
  1434.     WWindow *wwin, *tmp;
  1435.  
  1436.     if (!scr->focused_window || !scr->focused_window->flags.focused)
  1437.     val = None;
  1438.     else {
  1439.     val = (long)(scr->focused_window->client_win);
  1440.  
  1441.     /* raise the menubar thing */
  1442.     wwin = scr->focused_window;
  1443.     tmp = wwin->prev;
  1444.     while (tmp) {
  1445.         if (tmp->flags.kwm_menubar 
  1446.         && tmp->transient_for == wwin->client_win) {
  1447.         wRaiseFrame(tmp->frame->core);
  1448.         break;
  1449.         }
  1450.         tmp = tmp->prev;
  1451.     }
  1452.     }
  1453.     
  1454.     XChangeProperty(dpy, scr->root_win, _XA_KWM_ACTIVE_WINDOW,
  1455.             _XA_KWM_ACTIVE_WINDOW, 32, PropModeReplace, 
  1456.             (unsigned char*)&val, 1);
  1457.     XFlush(dpy);
  1458. }
  1459.  
  1460.  
  1461. void
  1462. wKWMUpdateWorkspaceCountHint(WScreen *scr)
  1463. {
  1464.     if (scr->flags.kwm_syncing_count)
  1465.     return;
  1466.  
  1467.     setSimpleHint(scr->root_win, _XA_KWM_NUMBER_OF_DESKTOPS,
  1468.           scr->workspace_count);
  1469.  
  1470.     sendToModules(scr, _XA_KWM_MODULE_DESKTOP_NUMBER_CHANGE, NULL,
  1471.           scr->workspace_count);
  1472. }
  1473.  
  1474.  
  1475. void
  1476. wKWMCheckDestroy(XDestroyWindowEvent *event)
  1477. {
  1478.     WScreen *scr;
  1479.  
  1480.     if (event->event == event->window) {
  1481.     return;
  1482.     }
  1483.  
  1484.     scr = wScreenSearchForRootWindow(event->event);
  1485.     if (!scr) {
  1486.     return;
  1487.     }
  1488.  
  1489.     removeModule(scr, event->window);
  1490.     removeDockWindow(scr, event->window);
  1491. }
  1492.  
  1493.  
  1494. void
  1495. wKWMUpdateWorkspaceNameHint(WScreen *scr, int workspace)
  1496. {
  1497.     char buffer[64];
  1498.  
  1499.     assert(workspace >= 0 && workspace < MAX_WORKSPACES);
  1500.  
  1501.     if (_XA_KWM_DESKTOP_NAME_[workspace]==0) {
  1502.     sprintf(buffer, "KWM_DESKTOP_NAME_%d", workspace + 1);
  1503.  
  1504.     _XA_KWM_DESKTOP_NAME_[workspace] = XInternAtom(dpy, buffer, False);
  1505.     }
  1506.  
  1507.     XChangeProperty(dpy, scr->root_win, _XA_KWM_DESKTOP_NAME_[workspace],
  1508.             XA_STRING, 8, PropModeReplace, 
  1509.             (unsigned char*)scr->workspaces[workspace]->name,
  1510.             strlen(scr->workspaces[workspace]->name)+1);
  1511.  
  1512.     sendToModules(scr, _XA_KWM_MODULE_DESKTOP_NAME_CHANGE, NULL, workspace+1);
  1513. }
  1514.  
  1515.  
  1516.  
  1517. void
  1518. wKWMUpdateClientWorkspace(WWindow *wwin)
  1519. {
  1520. #ifdef DEBUG1
  1521.     printf("updating workspace of %s to %i\n",
  1522.        wwin->frame->title, wwin->frame->workspace+1);
  1523. #endif
  1524.     setSimpleHint(wwin->client_win, _XA_KWM_WIN_DESKTOP, 
  1525.           wwin->frame->workspace+1);
  1526. }
  1527.  
  1528.  
  1529. void
  1530. wKWMUpdateClientGeometryRestore(WWindow *wwin)
  1531. {
  1532.     WArea rect;
  1533.     
  1534.     rect.x1 = wwin->old_geometry.x;
  1535.     rect.y1 = wwin->old_geometry.y;
  1536.     rect.x2 = wwin->old_geometry.x + wwin->old_geometry.width;
  1537.     rect.y2 = wwin->old_geometry.y + wwin->old_geometry.height;
  1538.     
  1539.     setAreaHint(wwin->client_win, _XA_KWM_WIN_GEOMETRY_RESTORE, rect);
  1540. }
  1541.  
  1542.  
  1543. void
  1544. wKWMUpdateClientStateHint(WWindow *wwin, WKWMStateFlag flags)
  1545. {
  1546.     if (flags & KWMIconifiedFlag) {
  1547.     setSimpleHint(wwin->client_win, _XA_KWM_WIN_ICONIFIED, 
  1548.               wwin->flags.miniaturized /*|| wwin->flags.shaded
  1549.               || wwin->flags.hidden*/);
  1550.     }
  1551.     if (flags & KWMStickyFlag) {
  1552.     setSimpleHint(wwin->client_win, _XA_KWM_WIN_STICKY, 
  1553.               IS_OMNIPRESENT(wwin));
  1554.     }
  1555.     if (flags & KWMMaximizedFlag) {
  1556.     setSimpleHint(wwin->client_win, _XA_KWM_WIN_MAXIMIZED, 
  1557.               wwin->flags.maximized!=0);
  1558.     }
  1559. }
  1560.  
  1561.  
  1562. Bool
  1563. wKWMGetUsableArea(WScreen *scr, WArea *area)
  1564. {
  1565.     char buffer[64];
  1566.  
  1567.     if (_XA_KWM_WINDOW_REGION_[0]==0) {
  1568.     sprintf(buffer, "KWM_WINDOW_REGION_%d", 1);
  1569.  
  1570.     _XA_KWM_WINDOW_REGION_[0] = XInternAtom(dpy, buffer, False);
  1571.     }
  1572.  
  1573.     return getAreaHint(scr->root_win, _XA_KWM_WINDOW_REGION_[0], area);
  1574. }
  1575.  
  1576.  
  1577.  
  1578. Bool
  1579. wKWMGetIconGeometry(WWindow *wwin, WArea *area)
  1580. {
  1581.     return getAreaHint(wwin->client_win, _XA_KWM_WIN_ICON_GEOMETRY, area);
  1582. }
  1583.  
  1584.  
  1585.  
  1586. #ifdef not_used
  1587. void
  1588. wKWMSetUsableAreaHint(WScreen *scr, int workspace)
  1589. {
  1590.     /* if we set this after making changes of our own to the area,
  1591.      * the next time the area changes, we won't know what should
  1592.      * be the new final area. This protocol isn't worth a shit :/
  1593.      */
  1594. /*
  1595.  * According to Matthias Ettrich:  
  1596.  * Indeed, there's no protocol to deal with the area yet in case several
  1597.  * clients want to influence it. It is sufficent, though, if it is clear
  1598.  * that one process is responsable for the area. For KDE this is kpanel, but
  1599.  * I see that there might be a conflict with the docking area of windowmaker
  1600.  * itself.
  1601.  * 
  1602.  */
  1603.  
  1604. #ifdef notdef
  1605.     char buffer[64];
  1606.  
  1607.     assert(workspace >= 0 && workspace < MAX_WORKSPACES);
  1608.  
  1609.     if (_XA_KWM_WINDOW_REGION_[workspace]==0) {
  1610.     sprintf(buffer, "KWM_WINDOW_REGION_%d", workspace+1);
  1611.  
  1612.     _XA_KWM_WINDOW_REGION_[workspace] = XInternAtom(dpy, buffer, False);
  1613.     }
  1614.  
  1615.     setAreaHint(scr->root_win, _XA_KWM_WINDOW_REGION_[workspace],
  1616.         scr->totalUsableArea);
  1617. #endif
  1618. }
  1619. #endif /* not_used */
  1620.  
  1621. void
  1622. wKWMSendEventMessage(WWindow *wwin, WKWMEventMessage message)
  1623. {
  1624.     Atom msg;
  1625.  
  1626.     if (wwin && (wwin->flags.internal_window
  1627.          || wwin->flags.kwm_hidden_for_modules
  1628.          || !wwin->flags.kwm_managed
  1629.          || WFLAGP(wwin, skip_window_list)))
  1630.     return;
  1631.  
  1632.     switch (message) {
  1633.      case WKWMAddWindow:
  1634.     msg = _XA_KWM_MODULE_WIN_ADD;
  1635.     break;
  1636.      case WKWMRemoveWindow:
  1637.     msg = _XA_KWM_MODULE_WIN_REMOVE;
  1638.     break;
  1639.      case WKWMFocusWindow:
  1640.     msg = _XA_KWM_MODULE_WIN_ACTIVATE;
  1641.     break;
  1642.      case WKWMRaiseWindow:
  1643.     msg = _XA_KWM_MODULE_WIN_RAISE;
  1644.     break;
  1645.      case WKWMLowerWindow:
  1646.     msg = _XA_KWM_MODULE_WIN_LOWER;
  1647.     break;
  1648.      case WKWMChangedClient:
  1649.     msg = _XA_KWM_MODULE_WIN_CHANGE;
  1650.     break;
  1651.      case WKWMIconChange:
  1652.     msg = _XA_KWM_MODULE_WIN_ICON_CHANGE;
  1653.     break;
  1654.      default:
  1655.     return;
  1656.     }
  1657.  
  1658.     sendToModules(wwin ? wwin->screen_ptr : NULL, msg, wwin, 0);
  1659. }
  1660.  
  1661.  
  1662. static void
  1663. writeSocket(int sock, char *data)
  1664. {
  1665.     char buffer[128];
  1666.  
  1667.     sprintf(buffer, "%i ", strlen(data));
  1668.     write(sock, buffer, strlen(buffer));
  1669.     write(sock, data, strlen(data));
  1670. }
  1671.  
  1672.  
  1673. static int
  1674. connectKFM(WScreen *scr)
  1675. {
  1676.     char *path;
  1677.     char buffer[128];
  1678.     char *ptr;
  1679.     FILE *f;
  1680.     int pid;
  1681.     int sock = 0;
  1682.     struct sockaddr_un addr;
  1683.  
  1684.     path = wstrappend(wgethomedir(), "/.kde/share/apps/kfm/pid");
  1685.     strcpy(buffer, getenv("DISPLAY"));
  1686.  
  1687.     ptr = strchr(buffer, ':');
  1688.     if (ptr)
  1689.     *ptr = '_';
  1690.  
  1691.     ptr = strrchr(buffer, '.');
  1692.     if (ptr)
  1693.     *ptr = 0;
  1694.     {
  1695.     char b[32];
  1696.     
  1697.     sprintf(b, ".%i", scr->screen);
  1698.     strcat(buffer, b);
  1699.     }
  1700.     ptr = path;
  1701.     path = wstrappend(ptr, buffer);
  1702.     free(ptr);
  1703.  
  1704.     /* pid file */
  1705.     f = fopen(path, "r");
  1706.     free(path);
  1707.     if (!f)
  1708.     return -1;
  1709.  
  1710.     buffer[0] = 0;
  1711.     fgets(buffer, 123, f);
  1712.     pid = atoi(buffer);
  1713.     if (pid <= 0)
  1714.     return -1;
  1715.  
  1716.     if (kill(pid, 0) != 0)
  1717.     return -1;
  1718.  
  1719.     buffer[0] = 0;
  1720.     fscanf(f, "%s", buffer);
  1721.     fclose(f);
  1722.  
  1723.     sock = socket(AF_UNIX, SOCK_STREAM, 0);
  1724.     if (sock < 0)
  1725.     return -1;
  1726.     addr.sun_family = AF_UNIX;
  1727.     strcpy(addr.sun_path, buffer);
  1728.  
  1729.     if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) < 0) {
  1730.     close(sock);
  1731.     return -1;
  1732.     }
  1733.  
  1734.     path = wstrappend(wgethomedir(), "/.kde/share/apps/kfm/magic");
  1735.     f = fopen(path, "r");
  1736.     if (!f) {
  1737.     return -1;
  1738.     }
  1739.     ptr = fgets(buffer, 123, f);
  1740.     fclose(f);
  1741.     if (!ptr) {
  1742.     return -1;
  1743.     }
  1744.     puts(buffer);
  1745.  
  1746.     ptr = wstrappend("auth", buffer);
  1747.  
  1748.     writeSocket(sock, ptr);
  1749.     free(ptr);
  1750.  
  1751.     return sock;
  1752. }
  1753.  
  1754.  
  1755. void
  1756. wKWMSelectRootRegion(WScreen *scr, int x, int y, int w, int h, Bool control)
  1757. {
  1758. #if 0
  1759.     char buffer[128];
  1760.     int sock;
  1761.  
  1762.     puts("CONNECTING");
  1763.     sock = connectKFM(scr);
  1764.     if (sock < 0)
  1765.     return;
  1766.     puts("SENDING DATA");
  1767.     
  1768.     sprintf(buffer, "selectRootIcons %i %i %i %i %c", x, y, w, h, control);
  1769.     writeSocket(sock, buffer);
  1770.     
  1771.     close(sock);
  1772. #endif
  1773. }
  1774.  
  1775.  
  1776. #endif /* KWM_HINTS */
  1777.